function KeyBindings(commander, bindings){
    this.init$Eventable();
    this.$commander = commander;
    this.$bindings = bindings || {};
    this.on(this, 'KeyDown', this._onKeyDown);
}

KeyBindings.prototype = {
    KEY_MAP: {
        8: 'BACKSPACE',
        9: 'TAB',
        38: 'UP',
        40: 'DOWN',
        37: 'LEFT',
        39: 'RIGHT',
        13: 'ENTER',
        112: 'F1',
        113: 'F2',
        114: 'F3',
        115: 'F4',
        116: 'F5',
        117: 'F6',
        118: 'F7',
        119: 'F8',
        120: 'F9',
        121: 'F10',
        122: 'F11',
        123: 'F12',
        46: 'DELETE',
        36: 'HOME',
        35: 'END',
        33: 'PAGE_UP',
        34: 'PAGE_DOWN',
        45: 'INSERT'
    },
    set: function (bindings){
        for (var k in bindings) {
            this.$bindings[k] = bindings[k];
        }
    },
    _onKeyDown: function (evt){
        var buff = [];
        if (evt.ctrlKey) {
            buff.push('CTRL');
        }
        if (evt.altKey || evt.metaKey) {
            buff.push('ALT');
        }
        if (evt.shiftKey) {
            buff.push('SHIFT');
        }
        buff.push(this.KEY_MAP[evt.keyCode] || String.fromCharCode(evt.keyCode));
        var key = buff.join('+');
        var noShiftKey = !evt.ctrlKey && !evt.altKey && evt.shiftKey &&
            (this.KEY_MAP[evt.keyCode] || String.fromCharCode(evt.keyCode));

        var bindings = this.$bindings;
        var command = bindings[key];
        var noShiftCommand = noShiftKey ? bindings[noShiftKey] : '';
        var ret = true;
        if (command != null) {
            if (typeof command === 'string') {
                ret = this.$commander.execCommand(command);
            } else {
                ret = command.call(this.$commander);
            }
        } else if (noShiftCommand) {
            if (typeof noShiftCommand === 'string') {
                ret = this.$commander.execCommand(noShiftCommand, true);
            } else {
                ret = noShiftCommand.call(this.$commander);
            }
        }
        if (ret !== true) {
            DOMUtils.preventDefault(evt);
        }
    }
};

Utils.extend(KeyBindings, Eventable);
